#include <cstring.h>

// uint32_t memcpyV1(void *dec, uint32_t dlen, const void *src, uint32_t slen)
// {
//     if (!(dec && src))
//     {
//         return 0;
//     }
//     dlen = (dlen > slen) ? slen : dlen;
//     memcpy(dec, src, dlen);
//     return dlen;
// }
void cstrFree(struct cstring *decs)
{
    if (!decs)
    {
        return;
    }
    decs->total = 0;
    decs->size = 0;
    if (!(decs->str))
    {
        return;
    }
    free(decs->str);
    decs->str = NULL;
}
static uint32_t cstrResetTotal(struct cstring *decs, uint32_t rlen)
{
    char *tmpptr = NULL;
    rlen++; // malloc + 1, for string write '\0'
    if (!decs)
    {
        return 0;
    }
    if (decs->total >= rlen)
    {
        return decs->total;
    }
    tmpptr = (char *)realloc(decs->str, rlen);
    // if realloc fail, decs->str[0] not be free!
    if (tmpptr)
    {
        decs->str = tmpptr;
        decs->total = rlen;
    }
    else
    {
        cstrFree(decs);
    }
    return decs->total;
}
uint32_t cstrResize(struct cstring *decs, uint32_t rlen)
{
    if (cstrResetTotal(decs, rlen) < 1)
    {
        return 0;
    }
    decs->size = rlen;
    if (decs->size < decs->total)
    {
        decs->str[decs->size] = 0;
    }
    return decs->size;
}
uint32_t cstrCpMem(struct cstring *decs, const void *srcs, uint32_t slen)
{
    if (!(decs && srcs && srcs && slen > 0))
    {
        return 0;
    }
    cstrResetTotal(decs, slen);
    if (!(decs->str))
    {
        return 0;
    }
    decs->size = memcpypro(decs->str, decs->total, srcs, slen);
    if (decs->size < decs->total)
    {
        decs->str[decs->size] = 0;
    }
    return decs->size;
}
uint32_t cstrCpStr(struct cstring *decs, const char *instr)
{
    if (!(instr))
    {
        return 0;
    }
    return cstrCpMem(decs, instr, strlen(instr));
}
uint32_t cstrCpCstr(struct cstring *decs, struct cstring *srcs)
{
    if (!(srcs))
    {
        return 0;
    }
    return cstrCpMem(decs, srcs->str, srcs->size);
}
uint32_t cstrCatMem(struct cstring *decs, const void *srcs, uint32_t slen)
{
    if (!(decs && srcs && srcs && slen > 0))
    {
        return 0;
    }
    cstrResetTotal(decs, decs->size + slen);
    if (!(decs->str))
    {
        return 0;
    }
    decs->size += memcpypro(decs->str + decs->size, slen, srcs, slen);
    if (decs->size < decs->total)
    {
        decs->str[decs->size] = 0;
    }
    return decs->size;
}
uint32_t cstrCatStr(struct cstring *decs, const char *instr)
{
    if (!(instr))
    {
        return 0;
    }
    return cstrCatMem(decs, instr, strlen(instr));
}
uint32_t cstrCatCstr(struct cstring *decs, struct cstring *srcs)
{
    if (!(srcs))
    {
        return 0;
    }
    return cstrCatMem(decs, srcs->str, srcs->size);
}
void cstrMvCstr(struct cstring *decs, struct cstring *srcs)
{
    if (!(decs && srcs))
    {
        return;
    }
    cstrFree(decs);
    (*decs) = (*srcs);
    *srcs = cstrInitVal;
}
uint32_t cstrSprint(struct cstring *decs, uint32_t maxsize, const char *format, ...)
{
    if (!decs)
    {
        return 0;
    }
    if (maxsize > 1024 * 1024)
    {
        printf("[%s,%d] print size too long:%u!\n", __func__, __LINE__, maxsize);
        return 0;
    }
    cstrResetTotal(decs, maxsize);
    if (!decs->str)
    {
        return 0;
    }
    va_list args;
    va_start(args, format);
    // printf比较耗时。尽量用一个。
    // 本来可以第一个vsnprintf来确认长度，分配相应空间然后再vsnprintf输出到数组。
    uint32_t tmplen = vsnprintf(decs->str, decs->total, format, args);
    va_end(args);
    if (tmplen < maxsize)
    {
        // vsnprintf返回字符串长度，没带结束符'\0'。
        // tmplen++;
    }
    else
    {
        // 超出范围，长度带了结束符'\0'
        // printf("[%s,%d]maybe data is over:%d,%d\n", __func__, __LINE__, (int)tmplen, (int)maxsize);
        tmplen = maxsize - 1;
    }
    decs->size = tmplen;
    return decs->size;
}
#if 0
int main()
{
    cstrDef(tmpStr);
    int a = 1, b = 2;
    cstrSprint(&tmpStr, 20, "my check print:a=%d,b=%d", a, b);
    logdebug("%s, %d, %d.", tmpStr.str, tmpStr.total, tmpStr.size);
    cstrDef(tmpStr1);
    cstrCpCstr(&tmpStr1, &tmpStr);
    logdebug("%s, %d, %d.", tmpStr1.str, tmpStr1.total, tmpStr1.size);
    cstrCatCstr(&tmpStr, &tmpStr1);
    logdebug("%s, %d, %d.", tmpStr.str, tmpStr.total, tmpStr.size);
    cstrMvCstr(&tmpStr1, &tmpStr);
    logdebug("%s, %d, %d.", tmpStr.str, tmpStr.total, tmpStr.size);
    logdebug("%s, %d, %d.", tmpStr1.str, tmpStr1.total, tmpStr1.size);
    cstrFree(&tmpStr);
    cstrFree(&tmpStr1);
    return 0;
}
#endif
